<template>
<div ref="waikCircle" class="waik-circle" :style="{width:`${diameter}px`,height:`${diameter + 6}px`}">
  <svg x="0" y="0" :viewBox="`0 0 ${diameter} ${diameter}`" :style="{width:`${diameter}px`,height:`${diameter}px`}">
    <circle
      cx="50%"
      cy="50%"
      :r="(diameter/2 - strokeWidth)"
      :stroke="layerColor"
      :stroke-width="strokeWidth-1"
      fill="none"
      :stroke-dasharray="len"
      :stroke-dashoffset=".5 * len"
      stroke-linecap="round"
    />

    <circle
      class="path"
      cx="50%"
      cy="50%"
      :r="(diameter/2 - strokeWidth)"
      :stroke="color"
      :stroke-width="strokeWidth"
      fill="none"
      :stroke-dasharray="len"
      :stroke-dashoffset="dashoffsetRate"
      stroke-linecap="round"
     />
     <circle class="point" :cx="cirPost.cx" :cy="cirPost.cy" :r="pointWidth" :stroke="pointStrokeColor" :stroke-width="pointStroke" :fill="pointColor" />
  </svg> 
</div>
</template>
<script>
import { reactive, ref, computed, onMounted, watch, toRefs } from 'vue'
import { tween } from 'shifty'
const MANUAL = 'manual'
const AUTO = 'auto'
const RE_FLOAT = /^\d+(\.\d+)?$/
const RE_INT = /^\[1-9][0-9]*$/
const RE_COLOR = /^#([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/
const isNumber = (v) => {
  return typeof v === 'number' || (
    typeof v === 'string' && (RE_FLOAT.test(v) || RE_INT.test(v))
  )
}

const extend = (target, source) => {
  for (let k in source) {
    target[k] = source[k]
  }
}
//获取指定节点的css指定样式
const getStyle = (dom,styleProp) => {
  if (window.getComputedStyle) {
    const style = document.defaultView.getComputedStyle(dom,null); 
    return style.getPropertyValue(styleProp)||style[styleProp]
  } else if (dom.currentStyle){
    return dom.currentStyle[styleProp];
  }
}
const getTranslateXY = (matrix) => {
  const val = matrix&&matrix.match(/^matrix(3d)?(.*)$/i)
  let translate = {x:0,y:0}
  if(val && val[2]){
    const tmp = val[2].replace(/ /g, '').split(',');
    translate.x = parseInt(tmp[val[1] ? 12 : 4], 10)
    translate.y = parseInt(tmp[val[1] ? 13 : 5], 10)
    return translate
  }
}

export default {
  name:'FCircle',
  props:{
    from:{ // 起始位置数字
      type: [Number,String],
      default: 1,
      validator: isNumber
    },
    duration: {
      type: [Number, String],
      default: 500,
      validator: isNumber
    },
    easing: {
      type: String,
      default: 'easeOutQuart'
    },
    currentRate:{ // 当前进度
      type: [Number,String],
      default: 1
    },
    rate:{  // 目标进度
      type: Number,
      default: 100
    },
    size:{ // 圆环直径
      type: [Number,String],
      default: 180
    },
    strokeWidth:{ // 进度条宽度
      type: Number,
      default: 5
    },
    layerColor:{  // 背景色
      type: String,
      default: 'white'
    },
    color:{  // 前景色
      type: String,
      default: '#1989fa'
    },
    pointWidth:{ // 点半点
      type: Number,
      default: 5
    },
    pointStroke:{ // 点边框
      type: Number,
      default: 4
    },
    pointColor:{  // 点前景色
      type: String,
      default: '#1989fa'
    },
    pointStrokeColor:{  // 点边框景色
      type: String,
      default: '#00C1FF'
    },

  },
  setup(props){
    const waikCircle = ref()
    const translate = reactive({x:0,y:0})

    // 数字变更
    const _from = ref(props.from)
    const _to = computed(()=>props.rate<props.currentRate?props.rate:(props.currentRate<0?0:props.currentRate))

    const num = ref(0)
    const options = reactive({easing:props.easing})
    const state = ref(0)

    const updateNumber = (data) => {
      const { state } = data
      const xx = !!state ? state : data
      num.value = xx.x
    }
    
    const makeOptions = () => {
      const from = typeof _from.value === 'string'
        ? { x: parseFloat(_from.value) }
        : { x: _from.value }

      const to = typeof _to.value === 'string'
        ? { x: parseFloat(_to.value) }
        : { x: _to.value }

      const duration = typeof props.duration === 'string'
        ? parseFloat(props.duration)
        : props.duration

      const step = updateNumber

      Object.assign(options, { from, to, duration, step })
    }

    const start = (ops) => {
      if (state.value > 0) return
      state.value = 1

      if (ops) extend(options, ops)
      if (options.duration === 0) options.duration = 1

      tween(options).then(updateNumber).then(() => {
        state.value = 0
        _from.value = _to.value
      })
    }
    watch([()=>_to.value,()=>props.size], ([_to_new,_size_new])=>{
      waikCircle.value&&Object.assign(translate,getTranslateXY(getStyle(waikCircle.value, "transform" )))
      makeOptions()
      start()
    },{immediate:true})

    // 圆弧运动
    const diameter =  computed(()=>{
      return props.size + Math.abs(translate.y) * 2
    })
    const len = computed(()=>{
      return 2 * Math.PI * (diameter.value/2 - props.strokeWidth)
    })
    const dashoffsetRate = computed(()=>{
      const value = len.value -  (num.value / (2*props.rate)) * len.value
      return value
    })
    
    const cirPost= computed(()=>{
      let smcd = props.pointWidth + props.pointStroke + props.strokeWidth
      let cd  = (diameter.value - smcd) /2,
          deg = (Math.PI * num.value) / props.rate,
          _cx = cd * Math.cos(deg),
          _cy = cd * Math.sin(deg);
      return {
        cx: _cx + cd + smcd/2,
        cy: _cy + cd + smcd/2
      }
    })

    onMounted(()=>{
      Object.assign(translate,getTranslateXY(getStyle(waikCircle.value, "transform" )))
    })

    return{
      diameter,
      len,
      dashoffsetRate,
      waikCircle,
      cirPost
    }
  }
}
</script>
<style lang="less" scoped>
.waik-circle{
  position: relative;
  display: inline-block;
  width: 100px;
  height: 100px;
  text-align: center;
  overflow: hidden;
  svg {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    transform: rotate(180deg);
  }
}
@keyframes run {
  to {
     stroke-dashoffset: 0;
  }
}
</style>